const models = require("../models/index.js");
const Client = models.Client;
const ClientDto = require("../dtos/client-dto.js");
const tokenService = require("../services/token-service.js");
const bcrypt = require("bcrypt");
const ApiError = require("../exceptions/api-error.js");
const mailService = require("./mail-service.js");
const password = require("../services/password-service.js");

class ClientService {
  // ----------------Авторизация---------------------------//--------------------------------------------

  async login(email, password) {
    const client = await Client.findOne({ where: { email } });
    if (!client) {
      throw ApiError.badRequest(`Пользователь с почтой ${email} не найден`);
    }
    const hashPassword = await bcrypt.compare(password, client.password);
    if (!hashPassword) {
      throw ApiError.badRequest(`Неверный пароль`);
    }

    const clientDto = new ClientDto(client);
    const tokens = tokenService.generateTokens({ ...clientDto });
    await tokenService.saveToken(clientDto.email, tokens.refreshToken);
    return { ...tokens, client: clientDto };
  }
  // --------------------Выход из учетной записи---------------------------//--------------------------------------------
  async logout(refreshToken) {
    const token = await tokenService.removeToken(refreshToken);
    return token;
  }
  // ------------------Добавление информации-------------------------//---------------------
  async addInfo(email, fullName) {
    const update = await Client.update(
      { fullName: fullName },
      { where: { email } }
    );
    if (!update) {
      throw ApiError.BadRequest(`Пользователь с почтой ${email} не существует`);
    }

    return {
      update,
    };
  }
  // ------------------Активация-------------------------//---------------------
  async activate(activationLink) {
    const client = await Client.findOne({ where: { activationLink } });
    if (!client) {
      throw ApiError.BadRequest(`Некорректная ссылка активации`);
    }
    client.isActivated = true;
    await client.save();
  }

  // ------------------сброс пароля -------------------------//---------------------
  async changePassword(token, oldpassword, newpassword) {
    const validToken = await tokenService.validateResetToken(token);
    const email = validToken.email;
    const client = await Client.findOne({ where: { email } });

    const hashPassword = await bcrypt.compare(oldpassword, client.password);
    if (!hashPassword) {
      throw ApiError.badRequest(`Неверный пароль`);
    }
    const hasрPasswordCompare = await bcrypt.compare(
      newpassword,
      client.password
    );
    if (hasрPasswordCompare) {
      throw new Error(`Новый пароль должен отличаться от старого`);
    }

    const hashNewPassword = await bcrypt.hash(newpassword, 5);
    const update = await Client.update(
      { password: hashNewPassword },
      { where: { email } }
    );
    return { update };
  }
  async resetPassword(email) {
    const client = await Client.findOne({ where: { email } });
    if (!client) {
      throw ApiError.badRequest(`Пользователь с почтой ${email} не существует`);
    }
    const resToken = tokenService.resetToken(email);
    console.log(resToken);

    await mailService.sendResetPasswordMail(
      email,
      `${process.env.API_URL}/api/client/change-password/${resToken}`
    );
    return resToken;
  }

  // ------------------Смена пароля-------------------------//---------------------
  async changePass(accessToken, oldpassword, newpassword) {
    const validToken = await tokenService.validateAccessToken(accessToken);

    const email = validToken.email;

    const changPass = await password.comparePass(
      oldpassword,
      newpassword,
      email
    );

    return changPass;
  }
  // ------- обновление аксес и рефреш токенов------
  async refresh(refreshToken) {
    if (!refreshToken) {
      throw ApiError.UnauthorizedError();
    }
    const clientData = tokenService.validateRefreshToken(refreshToken);
    const tokenFromDb = await tokenService.findToken(refreshToken);
    console.log(clientData, tokenFromDb);
    if (!clientData || !tokenFromDb) {
      throw ApiError.UnauthorizedError();
    }
    // //findbyid does not support
    const client = await Client.findOne({ where: { email: clientData.email } });
    const clientDto = new ClientDto(client);
    const tokens = tokenService.generateTokens({ ...clientDto });
    await tokenService.saveToken(clientDto.email, tokens.refreshToken);
    return {
      ...tokens,
      client: clientDto,
    };
  }
}

module.exports = new ClientService();
